package com.scrcu.cloud.wechat.home.endpoint.common.utils;

import com.scrcu.cloud.wechat.home.endpoint.common.constant.Constants;
import com.scrcu.cloud.wechat.home.endpoint.customer.exception.MyException;
import lombok.extern.slf4j.Slf4j;

import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @auther: siliang liu
 * @date: 2024/2/23 15:23
 * @description: 字符串操作工具类
 * @version: 1.0.0
 */

@Slf4j
public class StrUtil {

    public static final int INDEX_NOT_FOUND = -1;

    public static final String BASE_CHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

    /**
     * 字符串常量：空字符串 {@code ""}
     */
    public static final String EMPTY = "";

    /**
     * <p>字符串是否为空白，空白的定义如下：</p>
     * <ol>
     *     <li>{@code null}</li>
     *     <li>空字符串：{@code ""}</li>
     *     <li>空格、全角空格、制表符、换行符，等不可见字符</li>
     * </ol>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isBlank(null)     // true}</li>
     *     <li>{@code StrUtil.isBlank("")       // true}</li>
     *     <li>{@code StrUtil.isBlank(" \t\n")  // true}</li>
     *     <li>{@code StrUtil.isBlank("abc")    // false}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isEmpty(CharSequence)} 的区别是：
     * 该方法会校验空白字符，且性能相对于 {@link #isEmpty(CharSequence)} 略慢。</p>
     * <br>
     *
     * <p>建议：</p>
     * <ul>
     *     <li>该方法建议仅对于客户端（或第三方接口）传入的参数使用该方法。</li>
     *     <li>需要同时校验多个字符串时，建议采用 {@link #hasBlank(CharSequence...)} 或 {@link #isAllBlank(CharSequence...)}</li>
     * </ul>
     *
     * @param str 被检测的字符串
     * @return 若为空白，则返回 true
     * @see #isEmpty(CharSequence)
     */
    public static boolean isBlank(CharSequence str) {
        int length;

        if ((str == null) || ((length = str.length()) == 0)) {
            return true;
        }

        for (int i = 0; i < length; i++) {
            // 只要有一个非空字符即为非空字符串
            if (!isBlankChar(str.charAt(i))) {
                return false;
            }
        }

        return true;
    }


    public static boolean isDouble(String str) {
        try{
            Double.parseDouble(str);
            return true;
        }catch (Exception e1){
            return  false;
        }
    }

    /**
     * 为给定的长整型数字添加前导零，确保其总长度为20位。
     * 这对于创建统一大小的数字字符串非常有用，例如在数据格式化和排序时。
     *
     * @param num 需要添加前导零的长整型数字。
     *            可以是正数或负数，零将根据需要添加在数字的前面或后面。
     * @return 一个字符串，表示输入数字的零填充版本，总长度为20位。
     */
    public static String padZero(long num) {
        // 使用String.format将长整型数字转换为字符串，
        // 指定一个零填充的格式，总宽度为20位数字。
        return String.format("%020d", num);
    }

    /**
     * 在给定的时间字符串后添加特定长度的零填充字符串，以生成一个唯一标识符
     * 该方法主要用于生成一个具有固定长度的唯一标识符，其中包含时间信息和ID
     * 如果生成的随机数加上用户ID的长度小于所需的长度，则在前面补零
     * 如果最终字符串的长度不等于预设的最大长度，则抛出异常
     *
     * @param time 时间字符串，用于标识生成标识符的时间点
     * @param uid 用户ID，用于标识特定用户
     * @param length 生成的标识符的总长度
     * @return 生成的包含时间信息和ID的唯一标识符字符串
     * @throws MyException 如果生成的标识符长度不等于预设的最大长度，则抛出此异常
     */
    public static String padZero2(String time, long uid,int length) throws MyException {
        String finalstr = null;
        Random random = new Random();
        int randomNumber = random.nextInt(10000) + 1;
        if (randomNumber > 9999) {
            randomNumber = 9999;
        }
        String struid = randomNumber +String.valueOf(uid);
        if (struid.length() < length) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length - struid.length(); i++) {
                sb.append("0");
            }
            sb.append(struid);
            finalstr = time+sb.toString();
            if (finalstr.length()!= Constants.IDMAXLENGTH)
                throw new MyException();
            return finalstr;
        }
        finalstr = time+struid.substring(struid.length() - length);
        if (finalstr.length()!= Constants.IDMAXLENGTH)
            throw new MyException();
        return finalstr;
    }

    public static String padZero(String str) {
        if (str.length() < 24) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 24 - str.length(); i++) {
                sb.append("0");
            }
            sb.append(str);
            return sb.toString();
        }
        return str;
    }

    /**
     * 是否空白符<br>
     * 空白符包括空格、制表符、全角空格和不间断空格<br>
     *
     * @param c 字符
     * @return 是否空白符
     * @see Character#isWhitespace(int)
     * @see Character#isSpaceChar(int)
     * @since 4.0.10
     */
    public static boolean isBlankChar(int c) {
        return Character.isWhitespace(c)
                || Character.isSpaceChar(c)
                || c == '\ufeff'
                || c == '\u202a'
                || c == '\u0000';
    }

    /**
     * <p>字符串是否为非空白，非空白的定义如下： </p>
     * <ol>
     *     <li>不为 {@code null}</li>
     *     <li>不为空字符串：{@code ""}</li>
     *     <li>不为空格、全角空格、制表符、换行符，等不可见字符</li>
     * </ol>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isNotBlank(null)     // false}</li>
     *     <li>{@code StrUtil.isNotBlank("")       // false}</li>
     *     <li>{@code StrUtil.isNotBlank(" \t\n")  // false}</li>
     *     <li>{@code StrUtil.isNotBlank("abc")    // true}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isNotEmpty(CharSequence)} 的区别是：
     * 该方法会校验空白字符，且性能相对于 {@link #isNotEmpty(CharSequence)} 略慢。</p>
     * <p>建议：仅对于客户端（或第三方接口）传入的参数使用该方法。</p>
     *
     * @param str 被检测的字符串
     * @return 是否为非空
     * @see #isBlank(CharSequence)
     */
    public static boolean isNotBlank(CharSequence str) {
        return !isBlank(str);
    }

    /**
     * <p>指定字符串数组中，是否包含空字符串。</p>
     * <p>如果指定的字符串数组的长度为 0，或者其中的任意一个元素是空字符串，则返回 true。</p>
     * <br>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.hasBlank()                  // true}</li>
     *     <li>{@code StrUtil.hasBlank("", null, " ")     // true}</li>
     *     <li>{@code StrUtil.hasBlank("123", " ")        // true}</li>
     *     <li>{@code StrUtil.hasBlank("123", "abc")      // false}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isAllBlank(CharSequence...)} 的区别在于：</p>
     * <ul>
     *     <li>hasBlank(CharSequence...)            等价于 {@code isBlank(...) || isBlank(...) || ...}</li>
     *     <li>{@link #isAllBlank(CharSequence...)} 等价于 {@code isBlank(...) && isBlank(...) && ...}</li>
     * </ul>
     *
     * @param strs 字符串列表
     * @return 是否包含空字符串
     */
    public static boolean hasBlank(CharSequence... strs) {
        if (isEmpty(strs)) {
            return true;
        }

        for (CharSequence str : strs) {
            if (isBlank(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 数组是否为空
     *
     * @param <T>   数组元素类型
     * @param array 数组
     * @return 是否为空
     */
    public static <T> boolean isEmpty(T[] array) {
        return array == null || array.length == 0;
    }

    /**
     * <p>指定字符串数组中的元素，是否全部为空字符串。</p>
     * <p>如果指定的字符串数组的长度为 0，或者所有元素都是空字符串，则返回 true。</p>
     * <br>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isAllBlank()                  // true}</li>
     *     <li>{@code StrUtil.isAllBlank("", null, " ")     // true}</li>
     *     <li>{@code StrUtil.isAllBlank("123", " ")        // false}</li>
     *     <li>{@code StrUtil.isAllBlank("123", "abc")      // false}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #hasBlank(CharSequence...)} 的区别在于：</p>
     * <ul>
     *     <li>{@link #hasBlank(CharSequence...)}   等价于 {@code isBlank(...) || isBlank(...) || ...}</li>
     *     <li>isAllBlank(CharSequence...)          等价于 {@code isBlank(...) && isBlank(...) && ...}</li>
     * </ul>
     *
     * @param strs 字符串列表
     * @return 所有字符串是否为空白
     */
    public static boolean isAllBlank(CharSequence... strs) {
        if (isEmpty(strs)) {
            return true;
        }

        for (CharSequence str : strs) {
            if (isNotBlank(str)) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>字符串是否为空，空的定义如下：</p>
     * <ol>
     *     <li>{@code null}</li>
     *     <li>空字符串：{@code ""}</li>
     * </ol>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isEmpty(null)     // true}</li>
     *     <li>{@code StrUtil.isEmpty("")       // true}</li>
     *     <li>{@code StrUtil.isEmpty(" \t\n")  // false}</li>
     *     <li>{@code StrUtil.isEmpty("abc")    // false}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isBlank(CharSequence)} 的区别是：该方法不校验空白字符。</p>
     * <p>建议：</p>
     * <ul>
     *     <li>该方法建议用于工具类或任何可以预期的方法参数的校验中。</li>
     *     <li>需要同时校验多个字符串时，建议采用 {@link #hasEmpty(CharSequence...)} 或 {@link #isAllEmpty(CharSequence...)}</li>
     * </ul>
     *
     * @param str 被检测的字符串
     * @return 是否为空
     * @see #isBlank(CharSequence)
     */
    public static boolean isEmpty(CharSequence str) {
        return str == null || str.length() == 0;
    }

    /**
     * <p>字符串是否为非空白，非空白的定义如下： </p>
     * <ol>
     *     <li>不为 {@code null}</li>
     *     <li>不为空字符串：{@code ""}</li>
     * </ol>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isNotEmpty(null)     // false}</li>
     *     <li>{@code StrUtil.isNotEmpty("")       // false}</li>
     *     <li>{@code StrUtil.isNotEmpty(" \t\n")  // true}</li>
     *     <li>{@code StrUtil.isNotEmpty("abc")    // true}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isNotBlank(CharSequence)} 的区别是：该方法不校验空白字符。</p>
     * <p>建议：该方法建议用于工具类或任何可以预期的方法参数的校验中。</p>
     *
     * @param str 被检测的字符串
     * @return 是否为非空
     * @see #isEmpty(CharSequence)
     */
    public static boolean isNotEmpty(CharSequence str) {
        return !isEmpty(str);
    }

    /**
     * <p>是否包含空字符串。</p>
     * <p>如果指定的字符串数组的长度为 0，或者其中的任意一个元素是空字符串，则返回 true。</p>
     * <br>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.hasEmpty()                  // true}</li>
     *     <li>{@code StrUtil.hasEmpty("", null)          // true}</li>
     *     <li>{@code StrUtil.hasEmpty("123", "")         // true}</li>
     *     <li>{@code StrUtil.hasEmpty("123", "abc")      // false}</li>
     *     <li>{@code StrUtil.hasEmpty(" ", "\t", "\n")   // false}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isAllEmpty(CharSequence...)} 的区别在于：</p>
     * <ul>
     *     <li>hasEmpty(CharSequence...)            等价于 {@code isEmpty(...) || isEmpty(...) || ...}</li>
     *     <li>{@link #isAllEmpty(CharSequence...)} 等价于 {@code isEmpty(...) && isEmpty(...) && ...}</li>
     * </ul>
     *
     * @param strs 字符串列表
     * @return 是否包含空字符串
     */
    public static boolean hasEmpty(CharSequence... strs) {
        if (isEmpty(strs)) {
            return true;
        }

        for (CharSequence str : strs) {
            if (isEmpty(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * <p>指定字符串数组中的元素，是否全部为空字符串。</p>
     * <p>如果指定的字符串数组的长度为 0，或者所有元素都是空字符串，则返回 true。</p>
     * <br>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isAllEmpty()                  // true}</li>
     *     <li>{@code StrUtil.isAllEmpty("", null)          // true}</li>
     *     <li>{@code StrUtil.isAllEmpty("123", "")         // false}</li>
     *     <li>{@code StrUtil.isAllEmpty("123", "abc")      // false}</li>
     *     <li>{@code StrUtil.isAllEmpty(" ", "\t", "\n")   // false}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #hasEmpty(CharSequence...)} 的区别在于：</p>
     * <ul>
     *     <li>{@link #hasEmpty(CharSequence...)}   等价于 {@code isEmpty(...) || isEmpty(...) || ...}</li>
     *     <li>isAllEmpty(CharSequence...)          等价于 {@code isEmpty(...) && isEmpty(...) && ...}</li>
     * </ul>
     *
     * @param strs 字符串列表
     * @return 所有字符串是否为空白
     */
    public static boolean isAllEmpty(CharSequence... strs) {
        if (isEmpty(strs)) {
            return true;
        }

        for (CharSequence str : strs) {
            if (isNotEmpty(str)) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>指定字符串数组中的元素，是否都不为空字符串。</p>
     * <p>如果指定的字符串数组的长度不为 0，或者所有元素都不是空字符串，则返回 true。</p>
     * <br>
     *
     * <p>例：</p>
     * <ul>
     *     <li>{@code StrUtil.isAllNotEmpty()                  // false}</li>
     *     <li>{@code StrUtil.isAllNotEmpty("", null)          // false}</li>
     *     <li>{@code StrUtil.isAllNotEmpty("123", "")         // false}</li>
     *     <li>{@code StrUtil.isAllNotEmpty("123", "abc")      // true}</li>
     *     <li>{@code StrUtil.isAllNotEmpty(" ", "\t", "\n")   // true}</li>
     * </ul>
     *
     * <p>注意：该方法与 {@link #isAllEmpty(CharSequence...)} 的区别在于：</p>
     * <ul>
     *     <li>{@link #isAllEmpty(CharSequence...)}    等价于 {@code isEmpty(...) && isEmpty(...) && ...}</li>
     *     <li>isAllNotEmpty(CharSequence...)          等价于 {@code !isEmpty(...) && !isEmpty(...) && ...}</li>
     * </ul>
     *
     * @param args 字符串数组
     * @return 所有字符串是否都不为为空白
     * @since 5.3.6
     */
    public static boolean isAllNotEmpty(CharSequence... args) {
        return !hasEmpty(args);
    }

    /**
     * 是否存都不为{@code null}或空对象或空白符的对象，通过{@link #hasBlank(CharSequence...)} 判断元素
     *
     * @param args 被检查的对象,一个或者多个
     * @return 是否都不为空
     * @since 5.3.6
     */
    public static boolean isAllNotBlank(CharSequence... args) {
        return !hasBlank(args);
    }

    // ------------------------------------------------------------------------ startWith

    /**
     * 字符串是否以给定字符开始
     *
     * @param str 字符串
     * @param c   字符
     * @return 是否开始
     */
    public static boolean startWith(CharSequence str, char c) {
        if (isEmpty(str)) {
            return false;
        }
        return c == str.charAt(0);
    }

    // ------------------------------------------------------------------------ endWith

    /**
     * 字符串是否以给定字符结尾
     *
     * @param str 字符串
     * @param c   字符
     * @return 是否结尾
     */
    public static boolean endWith(CharSequence str, char c) {
        if (isEmpty(str)) {
            return false;
        }
        return c == str.charAt(str.length() - 1);
    }

    // ------------------------------------------------------------------------ contains


    /**
     * 指定字符串是否在字符串中出现过
     *
     * @param str       字符串
     * @param searchStr 被查找的字符串
     * @return 是否包含
     * @since 5.1.1
     */
    public static boolean contains(CharSequence str, CharSequence searchStr) {
        if (null == str || null == searchStr) {
            return false;
        }
        return str.toString().contains(searchStr);
    }

    /**
     * 查找指定字符串是否包含列表中的任意一个
     *
     * @param str        指定字符串
     * @param searchStrs 搜索的字符串
     * @return 是否包含
     * @since 5.1.1
     */
    public static boolean containsAny(CharSequence str, CharSequence... searchStrs) {
        if (isEmpty(str) || isEmpty(searchStrs)) {
            return false;
        }
        String s = str.toString();
        for (CharSequence searchStr : searchStrs) {
            if (s.contains(searchStr)) {
                return true;
            }
        }
        return false;
    }


    // ------------------------------------------------------------------------ repeat

    /**
     * 重复某个字符
     *
     * <pre>
     * StrUtil.repeat('e', 0)  = ""
     * StrUtil.repeat('e', 3)  = "eee"
     * StrUtil.repeat('e', -2) = ""
     * </pre>
     *
     * @param c     被重复的字符
     * @param count 重复的数目，如果小于等于0则返回""
     * @return 重复字符字符串
     */
    public static String repeat(char c, int count) {
        if (count <= 0) {
            return EMPTY;
        }

        char[] result = new char[count];
        for (int i = 0; i < count; i++) {
            result[i] = c;
        }
        return new String(result);
    }

    /**
     * 重复某个字符串
     *
     * @param str   被重复的字符
     * @param count 重复的数目
     * @return 重复字符字符串
     */
    public static String repeat(CharSequence str, int count) {
        if (null == str) {
            return null;
        }
        if (count <= 0 || str.length() == 0) {
            return EMPTY;
        }
        if (count == 1) {
            return str.toString();
        }

        // 检查
        final int len = str.length();
        final long longSize = (long) len * (long) count;
        final int size = (int) longSize;
        if (size != longSize) {
            throw new ArrayIndexOutOfBoundsException("Required String length is too large: " + longSize);
        }

        final char[] array = new char[size];
        str.toString().getChars(0, len, array, 0);
        int n;
        for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2
            System.arraycopy(array, 0, array, n, n);
        }
        System.arraycopy(array, 0, array, n, size - n);
        return new String(array);
    }

    /**
     * 有序的格式化文本，使用{number}做为占位符<br>
     * 通常使用：format("this is {0} for {1}", "a", "b") =》 this is a for b<br>
     *
     * @param pattern   文本格式
     * @param arguments 参数
     * @return 格式化后的文本
     */
    public static String indexedFormat(CharSequence pattern, Object... arguments) {
        return MessageFormat.format(pattern.toString(), arguments);
    }

    // ------------------------------------------------------------------------ length

    /**
     * 获取字符串的长度，如果为null返回0
     *
     * @param cs a 字符串
     * @return 字符串的长度，如果为null返回0
     * @since 4.3.2
     */
    public static int length(CharSequence cs) {
        return cs == null ? 0 : cs.length();
    }

    /**
     * 给定字符串数组的总长度<br>
     * null字符长度定义为0
     *
     * @param strs 字符串数组
     * @return 总长度
     * @since 4.0.1
     */
    public static int totalLength(CharSequence... strs) {
        int totalLength = 0;
        for (CharSequence str : strs) {
            totalLength += (null == str ? 0 : str.length());
        }
        return totalLength;
    }

    /**
     * 切换给定字符串中的大小写。大写转小写，小写转大写。
     *
     * <pre>
     * StrUtil.swapCase(null)                 = null
     * StrUtil.swapCase("")                   = ""
     * StrUtil.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
     * </pre>
     *
     * @param str 字符串
     * @return 交换后的字符串
     * @since 4.3.2
     */
    public static String swapCase(final String str) {
        if (isEmpty(str)) {
            return str;
        }

        final char[] buffer = str.toCharArray();

        for (int i = 0; i < buffer.length; i++) {
            final char ch = buffer[i];
            if (Character.isUpperCase(ch)) {
                buffer[i] = Character.toLowerCase(ch);
            } else if (Character.isTitleCase(ch)) {
                buffer[i] = Character.toLowerCase(ch);
            } else if (Character.isLowerCase(ch)) {
                buffer[i] = Character.toUpperCase(ch);
            }
        }
        return new String(buffer);
    }


    // ------------------------------------------------------------------------ other

    /**
     * 连接多个字符串为一个
     *
     * @param strs 字符串数组
     * @return 连接后的字符串
     * @since 4.1.0
     */
    public static String concat(CharSequence... strs) {
        final StringBuilder sb = new StringBuilder();
        for (CharSequence str : strs) {
            sb.append(str);
        }
        return sb.toString();
    }

    /**
     * 在给定字符串末尾填充指定字符，以达到给定长度<br>
     * 如果字符串本身的长度大于等于length，返回原字符串
     *
     * @param str       字符串
     * @param fixedChar 补充的字符
     * @param length    补充到的长度
     * @return 补充后的字符串
     * @since 5.8.0
     */
    public static String fixLength(CharSequence str, char fixedChar, int length) {
        final int fixedLength = length - str.length();
        if (fixedLength <= 0) {
            return str.toString();
        }
        return str + repeat(fixedChar, fixedLength);
    }

    /**
     * 数组中是否包含元素
     *
     * @param array 数组
     * @param value 被检查的元素
     * @return 是否包含
     * @since 3.0.7
     */
    public static boolean contains(char[] array, char value) {
        return indexOf(array, value) > INDEX_NOT_FOUND;
    }

    /**
     * 返回数组中指定元素所在位置，未找到返回{@link #INDEX_NOT_FOUND}
     *
     * @param array 数组
     * @param value 被检查的元素
     * @return 数组中指定元素所在位置，未找到返回{@link #INDEX_NOT_FOUND}
     * @since 3.0.7
     */
    public static int indexOf(char[] array, char value) {
        if (null != array) {
            for (int i = 0; i < array.length; i++) {
                if (value == array[i]) {
                    return i;
                }
            }
        }
        return INDEX_NOT_FOUND;
    }

    static String pattern = "\\$\\{(.*?)}";

    /**
     * 模板变量替换
     *
     * @param content 内容
     * @param value   值
     * @return str
     */
    public static String processTemplate(String content, Map<String, ?> value) {
        Pattern compile = Pattern.compile(pattern);
        Matcher matcher = compile.matcher(content);
        StringBuffer str = new StringBuffer();
        while (matcher.find()) {
            String group = matcher.group();
            matcher.appendReplacement(str, (String) value.get(group));
        }
        matcher.appendTail(str);
        return str.toString();
    }

    public static String replace(String str, int startInclude, int endExclude, char replacedChar) {
        if (isEmpty(str)) {
            return str;
        } else {
            int[] strCodePoints = str.codePoints().toArray();
            int length = strCodePoints.length;
            if (startInclude > length) {
                return str;
            } else {
                if (endExclude > length) {
                    endExclude = length;
                }
                if (startInclude > endExclude) {
                    return str;
                } else {
                    StringBuilder stringBuilder = new StringBuilder();
                    for (int i = 0; i < length; i++) {
                        if (i >= startInclude && i < endExclude) {
                            stringBuilder.append(replacedChar);
                        } else {
                            stringBuilder.append(new String(strCodePoints, i, 1));
                        }
                    }
                    return stringBuilder.toString();
                }
            }
        }
    }

    /**
     * 替换指定字符区间字符为 “*“ 号
     *
     * @param str          字符串
     * @param startInclude 开始位置（包含）
     * @param endExclude   结束为止（不包含）
     * @return 替换后的字符串
     */
    public static String hide(String str, int startInclude, int endExclude) {
        return replace(str, startInclude, endExclude, '*');
    }

    /**
     * 截取指定长度的字符串
     *
     * @param str    字符串
     * @param length 长度
     * @return str
     */
    public static String subString(String str, int length) {
        if (str == null) return EMPTY;
        if (length > str.length()) {
            length = str.length();
        }
        return str.substring(0, length);
    }

    /**
     * 生成指定位数随机字符串
     *
     * @param len 长度
     * @return str
     */
    public static String randomStr(int len) {
        StringBuilder sb = new StringBuilder();
        int baseLen = BASE_CHAR.length();
        for (int i = 0; i < len; i++) {
            int num = randomInt(baseLen);
            sb.append(BASE_CHAR.charAt(num));
        }
        return sb.toString();
    }

    /**
     * 生成随机数字
     *
     * @param limit 长度
     */
    private static int randomInt(int limit) {
        return ThreadLocalRandom.current().nextInt(limit);
    }

    /**
     * 如果字符串为空，返回默认值
     *
     * @param str          检查字符串
     * @param defaultValue 默认值
     * @return String
     */
    public static String emptyDefault(String str, String defaultValue) {
        return isEmpty(str) ? defaultValue : str;
    }

    /**
     * 将英文标点符号转换为中文标点符号。
     *
     * 此方法接收一个字符串输入，并返回一个字符串，其中英文的逗号、括号、冒号和分号被替换为中文对应的标点符号。
     * 这对于需要在中文环境下使用标点符号的场景非常有用，如中文文本处理、中文排版等。
     *
     * @param input 待处理的字符串，可能包含英文标点符号。
     * @return 替换了中文标点符号的字符串。
     */
    public static String strToCN(String input){
        return input.replace(",","，")
                .replace("(","（")
                .replace(")","）")
                .replace(":","：")
                .replace(";", "；");
    }

    /**
     * 获取一个字符串中间字符串
     *
     * @param input
     * @return String
     */
    public static String getMiddle(String input, String start,String end){
        int startIndex = input.indexOf(start);
        int endIndex = input.indexOf(end);
//        System.out.println("startIndex"+startIndex);
//        System.out.println("endIndex"+endIndex);
        if (startIndex>endIndex)
            endIndex = input.indexOf(end,startIndex);
//        System.out.println(endIndex);
        if (endIndex<0)
            return input.substring(startIndex+start.length());
        return input.substring(startIndex+start.length(),endIndex);
    }


    /**
     * 移除字符串末尾的非中英文文字和数字。
     *
     * 此方法主要针对字符串末尾的非单词字符进行处理，确保字符串以有效的中英文字符或数字结尾。
     * “非单词字符”在这里的定义包括任何不是字母、数字、下划线的部分。此外，该方法还考虑了中文字符，
     * 使得处理更加全面，适用于更多中文文本处理的场景。
     *
     * @param str 待处理的字符串。
     * @return 移除非中英文文字和数字后的字符串。如果原字符串为空或仅包含非中英文文字和数字，则返回空字符串。
     */
    public static String removeNonWord(String str) {
        // 使用正则表达式替换掉字符串末尾的所有非中英文文字和数字，实现移除功能。
        return str.replaceAll("[^\\w\\u4e00-\\u9fa5]+$", "");
    }

    /**
     * 移除字符串开头的所有非中文字符。
     *
     * 该方法通过正则表达式匹配并替换字符串开头的所有非中文字符，确保字符串的开头是中文。
     * 中文字符的定义范围是Unicode编码中的4E00-9FA5，覆盖了简体中文和繁体中文。
     *
     * @param str 待处理的字符串
     * @return 处理后的字符串，开头非中文字符被移除
     */
    public static String removeNonChineseStart(String str) {
        // 使用正则表达式替换掉字符串开头的所有非中文字符，实现移除功能。
        return str.replaceAll("^[^\\u4e00-\\u9fa5]+", "");
    }

    /**
     * 计算一个字符串在另一个字符串中出现的次数。
     *
     * @param source 源字符串，将在其中搜索目标字符串。
     * @param target 目标字符串，将计算其在源字符串中出现的次数。
     * @return 目标字符串在源字符串中出现的次数。
     */
    public static int countOccurrences(String source, String target) {
        int count = 0;
        int index = 0;
        while ((index = source.indexOf(target, index)) != -1) {
            count++;
            index += target.length();
        }
        return count;
    }

    public static void main(String[] args) {
        long uid = SnowWorkId.generateId();
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMddhhmmss");
        LocalDateTime createDate = LocalDateTime.now();
        String struid = null;
        try {
            struid = padZero2(createDate.format(dateFormatter),uid,24);
        } catch (MyException e) {
            e.printStackTrace();
        }
        System.out.println(struid);
    }
}